import { h, nextTick, resolveComponent } from "../vue.js"

if (typeof ReadableStream.prototype[Symbol.asyncIterator] !== "function") {
  Object.defineProperty(ReadableStream.prototype, Symbol.asyncIterator, {
    configurable: true,
    writable: true,
    value: async function* () {
      const reader = this.getReader()
      try {
        while (true) {
          const { done, value } = await reader.read()
          if (done) return
          yield value
        }
      } finally {
        reader.releaseLock()
      }
    },
  })
}

export default ctx => {
  ctx.page({
    name: 'WhatLang 解释器',
    path: '/cwhatlang',
    component: {
      render(_ctx, _cache, $props, $setup, $data, $options) {
        return h(resolveComponent("k-layout"), [
          h(resolveComponent("k-content"), [
            h(resolveComponent("el-input"), {
              type: "textarea",
              style: "font-family: monospace",
              modelValue: $data.code,
              "onUpdate:modelValue"(v) { $data.code = v },
              placeholder: "代码",
              autosize: { minRows: 1, maxRows: 10 },
              ref: "codeBox",
            }),
            h("div", { style: "margin: 0.5em 0" }, [
              h(resolveComponent("el-button"), { onClick: $options.run }, "运行"),
            ]),
            h(resolveComponent("el-input"), {
              type: "textarea",
              style: "font-family: monospace",
              modelValue: $data.output,
              placeholder: "输出",
              autosize: { minRows: 1, maxRows: 10 },
              readonly: true,
              ref: "outBox",
            }),
          ]),
        ])
      },
      data: () => ({
        code: localStorage.getItem("koishi.console.cwhatlang.code") || "`Hello, world!`",
        output: "",
        controller: null,
      }),
      watch: {
        code(v) {
          localStorage.setItem("koishi.console.cwhatlang.code", v)
        },
      },
      mounted() {
        this.$refs.codeBox.resizeTextarea()
        this.$refs.outBox.resizeTextarea()
      },
      unmounted() {
        this.controller?.abort()
      },
      methods: {
        getLoginToken() {
          try {
            const auth = localStorage.getItem("koishi.console.auth")
            if (auth) return JSON.parse(auth)?.token
          } catch {}
        },
        async run() {
          this.controller?.abort()
          this.output = ""
          const _controller = this.controller = new AbortController()
          const { signal } = _controller
          const headers = { "Content-Type": "text/plain" }
          const token = this.getLoginToken()
          if (token) headers["X-LNNBot-WhatServer-Login-Token"] = token
          const response = await fetch("/what/¿reqb^@", {
            method: "POST",
            headers,
            body: this.code,
            redirect: "manual",
            signal,
          })
          for await (const chunk of response.body.pipeThrough(new TextDecoderStream())) {
            if (this.controller !== _controller) return
            const outBox = this.$refs.outBox.textarea
            const doScroll = outBox.scrollTop + outBox.clientHeight >= outBox.scrollHeight - 1
            this.output += chunk
            if (doScroll) nextTick(() => { outBox.scrollBy(0, outBox.scrollHeight) })
          }
        },
      },
    },
  })
}
